package com.xuecheng.content.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.sun.corba.se.spi.ior.IdentifiableFactory;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.dto.TeachplanDTO;
import com.xuecheng.common.constant.ContentErrorCode;
import com.xuecheng.common.enums.common.AuditEnum;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.*;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.agent.MediaApiAgent;
import com.xuecheng.content.convert.TeachplanConvert;

import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.Teachplan;
import com.xuecheng.content.entity.TeachplanMedia;
import com.xuecheng.content.entity.ext.TeachplanNode;
import com.xuecheng.content.mapper.TeachplanMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.TeachplanMediaService;
import com.xuecheng.content.service.TeachplanService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;


import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 课程计划 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class TeachplanServiceImpl extends ServiceImpl<TeachplanMapper, Teachplan> implements TeachplanService {

    @Autowired
    private CourseBaseService courseBaseService;


    @Autowired
    private TeachplanMediaService teachplanMediaService;


    //业务分析：
    //    *   1.判断关键数据
    //    *       courseId companyId
    //    *   2.判断业务数据
    //    *       课程基础信息
    //    *           判断是否存在
    //    *           判断是否是同一家教学机构
    //    *           判断是否删除
    //    *   3.根据Courseid查询课程计划数据
    //    *   4.通过java的递归生成课程计划树形结构
    //    *   5.将数据转为dto并返回
    public TeachplanDTO queryTeachplanById(Long courseId, Long companyId) {
        //1.判断关键数据
        //           courseId companyId

        if (ObjectUtils.isEmpty(courseId) ||
                ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(ContentErrorCode.E_120101);
        }

        //2.判断业务数据
        //    课程基础信息
        //        判断是否存在
        //        判断是否是同一家教学机构
        //        判断是否删除
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseBase::getId, courseId);
        queryWrapper.eq(CourseBase::getCompanyId, companyId);

        CourseBase reliusbase = courseBaseService.getOne(queryWrapper);
        if (ObjectUtils.isEmpty(reliusbase)) {

            ExceptionCast.cast(ContentErrorCode.E_120013);
        }
        Integer status = reliusbase.getStatus();
        if (!(CommonEnum.USING_FLAG.getCodeInt().equals(status))) {
            ExceptionCast.cast(ContentErrorCode.E_120412);
        }

        // 3.根据Courseid查询课程计划数据
        TeachplanMapper baseMapper = this.getBaseMapper();
        List<TeachplanNode> nodes = baseMapper.selectByCourseId(courseId);

        //4.通过java的递归生成课程计划树形结构

        TeachplanDTO teachplanDTO = null;
        if (CollectionUtils.isEmpty(nodes)) {

            teachplanDTO = new TeachplanDTO();
        } else {

            TeachplanNode rootnodes = nodes.remove(0);

            generateTreeNodes(rootnodes, nodes);

            teachplanDTO = TeachplanConvert.INSTANCE.node2dto(rootnodes);
        }
        // 5.将数据转为dto并返回



        return teachplanDTO;

    }

    private void generateTreeNodes(TeachplanNode parentNode, List<TeachplanNode> nodes) {

        // 1.判断父级集合是否为空，如果为空需要创建
        if (CollectionUtils.isEmpty(parentNode.getChildrenNodes())) {
            ArrayList<TeachplanNode> childrens = new ArrayList<>(8);
            parentNode.setChildrenNodes(childrens);
        }

        // 2.循环遍历集合生成树形结构
        for (TeachplanNode node : nodes) {

            // 2.1 判断node是否和parentnode有关联，如果有关联将node存放到parentNode集合中
            if (ObjectUtils.nullSafeEquals(parentNode.getId(),node.getParentid())) {

                parentNode.getChildrenNodes().add(node);

                // 2.2 生成node集合数据
                // 如果是第三级课程计划，无需递归
                if (!(TeachPlanEnum.THIRD_LEVEL.equals(node.getGrade()))) {
                    generateTreeNodes(node, nodes);
                } else {
                    // 如果是第三级课程计划，需要查询是否有关联的媒资信息
                    LambdaQueryWrapper<TeachplanMedia> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(TeachplanMedia::getTeachplanId, node.getId());
                    queryWrapper.eq(TeachplanMedia::getCourseId, node.getCourseId());

                    TeachplanMedia teachplanMedia = teachplanMediaService.getOne(queryWrapper);

                    if (!(ObjectUtils.isEmpty(teachplanMedia))) {
                        node.setTeachplanMedia(teachplanMedia);
                    }
                }
            }
        }

    }

    //业务分析：
    //    *   主体方法
    //    *       1.判断业务操作
    //    *           判断是创建还是修改：teachplanId
    //    *           如果有:修改
    //    *           如果没有:创建
    //    *
    //    *       2.执行创建和修改操作并返回dto数据
    //    *
    //    *       3.返回结果数据dto
    @Transactional
    public TeachplanDTO createOrSetTeachPlan(TeachplanDTO dto, Long companyid) {

        TeachplanDTO teachplanDTO = null;
        if (ObjectUtils.isEmpty(dto.getTeachPlanId())) {
            teachplanDTO = createTeachplan(dto,companyid);
        } else {
            teachplanDTO = setTeachplan(dto,companyid);
        }

        return teachplanDTO;
    }


    /*
     * 主体方法业务分析：
     *   1.判断关键数据
     *   2.判断业务数据
     *       课程基础信息
     *           判断是否存在
     *           判断是否同一家机构
     *           判断是否删除
     *           判断课程基础信息审核状态：未提交和审核未通过
     *   3.获得父级数据并进行关联
     *       parentid
     *       grade：子级grade是父级grade+1
     *       orderby：获得父级课程计划的子级数据个数+1（bug）
     *   4.将dto转为po并保存
     *   5.判断保存后的结果
     *   6.将数据库最新数据转为dto并返回
     *
     * */
    private TeachplanDTO createTeachplan(TeachplanDTO dto, Long companyid) {
//        1.判断关键数据
//        2.判断业务数据
//                *       课程基础信息
//                *           判断是否存在
//                *           判断是否同一家机构
//                *           判断是否删除
//                *           判断课程基础信息审核状态：未提交和审核未通过
        CourseBaseDTO courseBase = createorsetMsg(dto, companyid);

        //3.获得父级数据并进行关联
        //     *       parentid
        //     *       grade：子级grade是父级grade+1
        //     *       orderby：获得父级课程计划的子级数据个数+1（bug）

        Teachplan teachplan = TeachplanConvert.INSTANCE.dto2entity(dto);

        Teachplan parentNode =  generateParentNode(dto,courseBase);

        teachplan.setParentid(parentNode.getId());
        teachplan.setGrade(parentNode.getGrade()+1);

        LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Teachplan::getParentid,parentNode.getId());

        int count = this.count(queryWrapper);
        teachplan.setOrderby(count+1);

        boolean save = this.save(teachplan);
        if (!save) {
            ExceptionCast.cast(ContentErrorCode.E_120407);
        }
        //4.将dto转为po并保存
        Teachplan po = this.getById(teachplan.getId());

        TeachplanDTO teachplanDTO = TeachplanConvert.INSTANCE.entity2dto(po);

        //5.判断保存后的结果
        //6.将数据库最新数据转为dto并返回
        return teachplanDTO;

    }

    private CourseBaseDTO createorsetMsg(TeachplanDTO dto, Long companyid) {
        if (ObjectUtils.isEmpty(companyid) ||
                StringUtil.isBlank(dto.getPname()) ||
                ObjectUtils.isEmpty(dto.getCourseId())
                        ){
            ExceptionCast.cast(ContentErrorCode.E_120101);
        }
        CourseBaseDTO courseBase = courseBaseService.getCourseBase(dto.getCourseId(), companyid);


        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)
        ){
            ExceptionCast.cast(ContentErrorCode.E_120015);
        }
        return courseBase;
    }

    /*
     * 业务分析：
     *   1.判断新增数据是二级还是三级课程计划
     *       判断新增数据是否有parentId值
     *           如果有：三级课程计划
     *           如果没有：二级课程计划
     *   2.获得二级课程计划的父级数据
     *       查询数据库获得一级课程计划：courseId、parentid=0
     *           如果没有：自动创建并保存数据--数据来源 coursebase
     *           如果有：直接返回
     *   3.获得三级课程计划的父级数据
     *       查询数据库获得二级课程计划：parentId
     *           如果没有：直接抛出异常
     *           如果有：直接返回
     * */
    private Teachplan generateParentNode(TeachplanDTO dto, CourseBaseDTO courseBase) {
        //1.判断新增数据是二级还是三级课程计划
        //     *       判断新增数据是否有parentId值
        //     *           如果有：三级课程计划
        //     *           如果没有：二级课程计划
        Long parentid = dto.getParentid();
        if (ObjectUtils.isEmpty(parentid)){
            //如果有：三级课程计划
            // 如果没有：二级课程计划
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getCourseId,courseBase.getCourseBaseId());
            queryWrapper.eq(Teachplan::getParentid,TeachPlanEnum.FIRST_PARENTID_FLAG);

            Teachplan rootnode = this.getOne(queryWrapper);

            if (ObjectUtils.isEmpty(rootnode)) {

                //2.获得二级课程计划的父级数据
                // 查询数据库获得一级课程计划：courseId、parentid=0
                //     如果没有：自动创建并保存数据--数据来源 coursebase
                //     如果有：直接返回
                rootnode = new Teachplan();
                rootnode.setPname(courseBase.getName());
                rootnode.setParentid(new Long(TeachPlanEnum.FIRST_PARENTID_FLAG));
                rootnode.setGrade(TeachPlanEnum.FIRST_LEVEL);
                rootnode.setDescription(courseBase.getDescription());
                rootnode.setOrderby(TeachPlanEnum.FIRST_LEVEL);
                rootnode.setCourseId(courseBase.getCourseBaseId());
                boolean save = this.save(rootnode);

                if (!save) {
                    ExceptionCast.cast(ContentErrorCode.E_120415);
                }
            }
            return rootnode;
        }else {
            //3.获得三级课程计划的父级数据
            //    查询数据库获得二级课程计划：parentId
            //        如果没有：直接抛出异常
            //        如果有：直接返回

            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getId,parentid);

            Teachplan teachplan = this.getOne(queryWrapper);

            if (ObjectUtils.isEmpty(teachplan)) {

            ExceptionCast.cast(ContentErrorCode.E_120408);
            }
            return teachplan;
        }

    }

    /*
    * 业务分析：
    *    1.判断关键数据
         2.判断业务数据
             课程基础信息
                 判断是否存在
                 判断是否同一家机构
                 判断是否删除
                 判断课程基础信息审核状态：未提交和审核未通过
             课程计划
                 判断是否存在
         3.修改课程计划数据
              pname starttime endtime is_preview
         4.判断修改后的结果
         5.将数据库最新的数据转为dto并返回
    * */
    private TeachplanDTO setTeachplan(TeachplanDTO dto, Long companyid) {
        //1.判断关键数据
        //2.判断业务数据
        //        课程基础信息
        //判断是否存在
        //        判断是否同一家机构
        //判断是否删除
        //判断课程基础信息审核状态：未提交和审核未通过
        //        课程计划
        //判断是否存在
        createorsetMsg(dto,companyid);

        //3.修改课程计划数据
        //              pname starttime endtime is_preview
        LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Teachplan::getId,dto.getTeachPlanId());
        int count = this.count(queryWrapper);
        if (count < 1) {
            ExceptionCast.cast(ContentErrorCode.E_120402);
        }
        //修改课程计划
        LambdaUpdateWrapper<Teachplan> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Teachplan::getPname, dto.getPname());
        updateWrapper.set(Teachplan::getStartTime, dto.getStartTime());
        updateWrapper.set(Teachplan::getEndTime, dto.getEndTime());
        updateWrapper.set(Teachplan::getIsPreview, dto.getIsPreview());

        updateWrapper.eq(Teachplan::getId, dto.getTeachPlanId());

        //         4.判断修改后的结果
        boolean update = this.update(updateWrapper);
        if (!update) {
            ExceptionCast.cast(ContentErrorCode.E_120407);
        }
        //         5.将数据库最新的数据转为dto并返回
        Teachplan po = this.getById(dto.getParentid());

        TeachplanDTO teachplanDTO = TeachplanConvert.INSTANCE.entity2dto(po);


        return teachplanDTO;
    }

    //业务操作：
    //1.判断关键
    //	teachplanId  companyId
    //2.判断业务数据
    //	课程基础信息
    //	判断是否存在、判断是否是同一家教学机构、判断是否删除、判断审核状态（未提交、审核未通过）
    //	课程计划
    //	判断删除的课程计划是几级数据
    //		二级
    //		判断是否存在子级数据，如果有不让删除
    //	    三级
    //	如果是录播课程
    //	判断课程计划是否有关联数据（查询TeachplanMedia表数据）
    public void delectteachPlant(Long teachPlanId, Long companyid) {

        //1.判断关键
        //	teachplanId  companyId
        Teachplan teachplan = this.getById(teachPlanId);
        if (ObjectUtils.isEmpty(teachplan)) {
            ExceptionCast.cast(ContentErrorCode.E_120402);
        }
        //2.判断业务数据
        //	课程基础信息
        CourseBase courseBase = courseBaseService.getById(teachplan.getCourseId());
        if (ObjectUtils.isEmpty(courseBase)) {
            ExceptionCast.cast(ContentErrorCode.E_120403);
        }

        //	判断是否存在、判断是否是同一家教学机构、判断是否删除、判断审核状态（未提交、审核未通过）
        if (!(ObjectUtils.nullSafeEquals(courseBase.getCompanyId(),companyid))) {
            ExceptionCast.cast(ContentErrorCode.E_120416);
        }


        if ((ObjectUtils.isEmpty(CommonEnum.USING_FLAG))){
            ExceptionCast.cast(ContentErrorCode.E_120412);
        }
        Integer status = courseBase.getStatus();
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(status) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(status) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(status)
        ) {
//            throw new RuntimeException("课程的审核状态");
            ExceptionCast.cast(ContentErrorCode.E_120014);
        }
        //课程计划
        // 	判断删除的课程计划是几级数据
        if (teachplan.getGrade() == TeachPlanEnum.SECEND_LEVEL) {
            // 		二级
            // 		判断是否存在子级数据，如果有不让删除
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getParentid, teachPlanId);
            int count = count(queryWrapper);


            if (count > 0) {
                ExceptionCast.cast(ContentErrorCode.E_120409);
                // 	    三级
            }
        }else {
            // 判断二级课程计划是否有子级课程计划信息
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getParentid, teachPlanId);
            int count = count(queryWrapper);


            if (count > 0)
                ExceptionCast.cast(ContentErrorCode.E_120409);
        }

        //	如果是录播课程
        //	判断课程计划是否有关联数据（查询TeachplanMedia表数据）
       /* if (ObjectUtils.isEmpty(CourseModeEnum.COURSE_MODE_COMMON_STATUS) ||
                ObjectUtils.isEmpty(CourseModeEnum.COURSE_MODE_RECORD_STATUS)
        ) {
            LambdaQueryWrapper<TeachplanMedia> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.select(TeachplanMedia::getCoursePubId);

        }else {
            ExceptionCast.cast(ContentErrorCode.E_120023);
        }*/
        removeById(teachPlanId);
    }
}
